import numpy as np
import platgo as pg


def eliptic(X: np.ndarray) -> np.ndarray:
    return np.sum(10**(6*np.linspace(0, 1, X.shape[1]))*X**2, axis=1)


def tosz(X: np.ndarray) -> np.ndarray:
    X1 = np.zeros(X.shape)
    X1[X != 0] = np.log(np.abs(X[X != 0]))
    C1 = np.zeros(X.shape) + 5.5
    C1[X > 0] = 10
    C2 = np.zeros(X.shape) + 3.1
    C2[X > 0] = 7.9
    Z = np.sign(X) * np.exp(X1 + 0.049 * (np.sin(C1*X1)+np.sin(C2*X1)))
    return Z


class CEC2013_F1(pg.Problem):

    def __init__(self):
        self.name = 'CEC2013_F1'
        self.type['single'], self.type['real'], self.type['large'] = [True] * 3
        self.M = 1
        self.D = 1000
        lb = [-100] * self.D
        ub = [100] * self.D
        self.x_opt = np.loadtxt('cec2013_1.txt')
        self.borders = np.array([lb, ub])
        super().__init__()

    def cal_obj(self, pop: pg.Population) -> None:
        pop.objv = np.array([eliptic(tosz(pop.decs - self.x_opt))]).T

    def get_optimal(self) -> np.ndarray:
        pass


if __name__ == '__main__':
    problem = CEC2013_F1()
    alg = pg.algorithms.GA(problem=problem, maxgen=10000)
    pop = alg.go(100)
    print(pop)